package app

import "math"

// Runoff 流域产流
type Runoff struct {

	//========模型参数========//
	WM  float64 `json:"WM"`  //流域平均张力水容量/mm，不敏感，120~200
	B   float64 `json:"B"`   //张力水蓄水容量曲线方次，不敏感，0.1~0.4
	IM  float64 `json:"IM"`  // 不透水面积占全流域面积的比例，不敏感
	WUM float64 `json:"WUM"` //上层张力水容量/mm，敏感，10~50
	WLM float64 `json:"WLM"` //下层张力水容量/mm，敏感，60~90
	WDM float64 `json:"WDM"` // //深层张力水容量/mm，等于WM - WUM - WLM，不属于参数
	////========模型状态========//
	R float64 `json:"R"`
	//double R;	//总径流量，mm
	RIM float64 `json:"RIM"`
	//double RIM;   //不透水面积上的产流量，mm
	W float64 `json:"W"`
	//double W;	//流域平均初始土壤含水量，mm
	WU float64 `json:"WU"` //上层张力水蓄量，mm
	//double WU;   //上层张力水蓄量，mm
	WL float64 `json:"WL"` //下层张力水蓄量，mm
	//double WL;   //下层张力水蓄量，mm
	WD float64 `json:"WD"` //深层张力水蓄量，mm
	//double WD;   //深层张力水蓄量，mm
	WMM float64 `json:"WMM"` //包气带蓄水容量最大值，mm
	//double WMM;   //包气带蓄水容量最大值，mm
	A float64 `json:"A"` //初始土壤含水量最大值，mm
	//double A;    //初始土壤含水量最大值，mm
	EU float64 `json:"EU"`
	//double EU;   //上层蒸散发量，mm
	EL float64 `json:"EL"`
	//double EL;   //下层蒸散发量，mm
	ED float64 `json:"ED"`
	//double ED;   //深层蒸散发量，mm
	EP float64 `json:"EP"`
	//double EP;   //流域蒸发能力，mm
	PE float64 `json:"PE"`
	//double PE;	//净雨量，mm

	////========外部输入========//
	P float64 `json:"P"`
	//double P;    //降雨量，mm

}

func (e *Runoff) SetParams(para *Params) {
	// 设置默认的参数
	e.WM = 120.0
	e.B = 0.2
	e.WUM = 20.0
	e.WLM = 80.0
	e.WDM = 20.0
	e.WL = 30.0
	e.WU = 10.0
	e.WL = 30.0
	e.WD = 20.0

	e.WUM = para.MUM
	e.WLM = para.MLM
	e.B = para.MB
	e.IM = para.MIM
	e.WM = para.MWM
	//e.WDM = para.MWM - para.MUM - para.MUM

}

func (e *Runoff) SetState(s *State) {
	e.WU = s.WU
	e.WL = s.WL
	e.WD = s.WD
	e.W = s.W // 要注意是否设置正确的值
	e.P = s.P // 要注意是否设置正确的值
	e.EU = s.EU
	e.EL = s.EL
	e.ED = s.ED
	e.EP = s.EP
}

func (e *Runoff) Calculate() {
	e.PE = e.P - e.EU - e.EL - e.ED
	//这里认为净雨量小于1e-5时即为小于等于0
	if e.PE <= 1e-5 {
		e.R = 0.0
		e.PE = 0.0
		e.RIM = 0.0
	} else {
		//WMM=(1+B)*WM/(1-IM) 要吸收这么多水才产流
		e.WMM = (1 + e.B) * e.WM / (1 - e.IM)
		//a = WMM * (1 - (1 - W / WM) ** (1 / (B + 1))) 能产流的水
		e.A = e.WMM * (1 - math.Pow(1-e.W/e.WM, 1/(e.B+1)))
		if e.A+e.PE < e.WMM {
			// 前期含水量+净雨<全流域最大蓄水量, 部分面积产流
			e.R = e.PE + e.W - e.WM + e.WM*math.Pow(1-(e.A+e.PE)/e.WMM, e.B+1)
		} else {
			// 前期含水量+净雨>全流域最大蓄水量, 全流域产流
			e.R = e.PE - (e.WM - e.W)
		}
		e.RIM = e.PE * e.IM //计算不透水面积上的产流量
	}

	//	计算下一阶段的产流
	e.WU = e.WU + e.P - e.EU - e.R
	e.WL = e.WL - e.EL
	e.WD = e.WD - e.ED

	if e.WD < 0 {
		e.WD = 0 //防止深层张力水蓄量小于0
	}

	//放置张力水蓄量超上限
	if e.WU > e.WUM {
		e.WL = e.WL + e.WU - e.WUM
		e.WU = e.WUM
	}
	if e.WL > e.WLM {
		e.WD = e.WD + e.WL - e.WLM
		e.WL = e.WLM
	}

	e.WDM = e.WM - e.WUM - e.WLM //计算深层张力水容量
	if e.WD > e.WDM {
		e.WD = e.WDM
	}
	//计算土壤含水量
	e.W = e.WU + e.WL + e.WD

}

func (e *Runoff) UpdateState(s *State) {
	s.WU = e.WU
	s.WL = e.WL
	s.WD = e.WD
	s.W = e.W
	s.RIM = e.RIM
	s.R = e.R
	s.PE = e.PE
}
